package com.strong.sample.table.t_unit.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.strong.sample.table.t_unit.TableUnitConstants;
import com.strong.sample.table.t_unit.jpa.TableUnitDAO;
import com.strong.sample.table.t_unit.jpa.TableUnitDO;
import com.strong.sample.table.t_unit.jpa.TableUnitDO_;
import com.strong.sample.table.t_unit.model.TableUnitCreateDTO;
import com.strong.sample.table.t_unit.model.TableUnitRetrieveDTO;
import com.strong.sample.table.t_unit.model.TableUnitUpdateDTO;
import com.strong.sample.table.t_unit.model.TableUnitVO;
import com.strong.utils.JSON;
import com.strong.utils.StrongUtils;
import com.strong.utils.jpa.service.StrongServiceImpl;
import com.strong.utils.message.StrongMessageSource;
import jakarta.persistence.criteria.Predicate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static com.strong.utils.jpa.JpaConstants.*;

/**
 * 单位表 数据处理Service实现类
 *
 * @author Simen
 * @date 2022-02-07 20:11:23
 */
@Slf4j
@Service
@CacheConfig(cacheNames = {TableUnitConstants.TABLE_ENTITY})
public class TableUnitServiceImpl extends StrongServiceImpl<TableUnitDO, TableUnitVO> implements TableUnitService {

    /**
     * 注入的消息处理类
     */
    private final StrongMessageSource messageSource;

    /**
     * 注入的DAO类
     */
    private final TableUnitDAO tableUnitDAO;

    /**
     * 实例化
     *
     * @param messageSource 注入的消息处理类
     * @param tableUnitDAO  注入的DAO类
     */
    @Autowired
    public TableUnitServiceImpl(StrongMessageSource messageSource, TableUnitDAO tableUnitDAO) {
        this.messageSource = messageSource;
        this.tableUnitDAO = tableUnitDAO;
    }

    @Override
    @Cacheable(key = "#root.target + '_' + #root.methodName + '_' + #intId")
    public TableUnitDO getRecord(final Integer intId) {
        log.debug(intId.toString());
        Assert.notNull(intId, MSG_QUERY_ID_EMPTY);
        return tableUnitDAO.getReferenceById(intId);
    }

    @Override
    @CacheEvict(allEntries = true)
    public TableUnitDO getCreateAction(final TableUnitCreateDTO modelCreate) {
        log.debug(JSON.toJSONString(modelCreate));
        Assert.notNull(modelCreate, MSG_CONTENT_EMPTY);

        TableUnitDO entity = BeanUtil.toBean(modelCreate, TableUnitDO.class, CopyOptions.create().setIgnoreNullValue(true));
        // 初始化实体类ID
        entity.setUnitId(StrongUtils.getNoRepeatId(tableUnitDAO::getCountById));
        tableUnitDAO.save(entity);
        return entity;
    }

    @Override
    @Cacheable(keyGenerator = "vabKeyGenerator")
    public List<TableUnitDO> getAllList(final TableUnitRetrieveDTO modelRetrieve) {
        log.debug(JSON.toJSONString(modelRetrieve));
        Assert.notNull(modelRetrieve, MSG_SEARCH_CONDITION_EMPTY);

        // 以表达式生成一个查询条件对象
        Specification<TableUnitDO> specification = getSpecification(modelRetrieve);
        return tableUnitDAO.findAll(specification, modelRetrieve.getSort());
    }

    @Override
    @Cacheable(keyGenerator = "vabKeyGenerator")
    public Page<TableUnitDO> getPageList(final TableUnitRetrieveDTO modelRetrieve) {
        log.debug(JSON.toJSONString(modelRetrieve, true));
        Assert.notNull(modelRetrieve, MSG_SEARCH_CONDITION_EMPTY);

        // 以表达式生成一个查询条件对象
        Specification<TableUnitDO> specification = getSpecification(modelRetrieve);
        return tableUnitDAO.findAll(specification, modelRetrieve.getPageable());
    }

    @Override
    @CacheEvict(allEntries = true)
    public TableUnitDO getUpdateAction(final TableUnitUpdateDTO modelUpdate) {
        log.debug(JSON.toJSONString(modelUpdate));
        Assert.notNull(modelUpdate, MSG_CONTENT_EMPTY);

        // 通过id字段获取待修改的实体类（id字段不存在，需修改为对应字段）
        TableUnitDO entity = tableUnitDAO.getReferenceById(modelUpdate.getUnitId());
        Assert.notNull(entity, MSG_RECORD_NONENTITY);
        BeanUtil.copyProperties(modelUpdate, entity, CopyOptions.create().setIgnoreNullValue(true));
        tableUnitDAO.save(entity);
        return entity;
    }

    @Override
    @Cacheable(key = "#root.target + '_' + #root.methodName + '_' + #intId")
    public TableUnitDO getUpdateRecord(final Integer intId) {
        log.debug(intId.toString());
        Assert.notNull(intId, MSG_QUERY_ID_EMPTY);
        return tableUnitDAO.getReferenceById(intId);
    }

    @Override
    @CacheEvict(allEntries = true)
    public Integer[] getDeleteAction(final Integer... intsId) {
        log.debug(ArrayUtil.toString(intsId));
        Assert.notEmpty(intsId, MSG_DELETE_RECORD_EMPTY);

        int[] intsTemp = new int[intsId.length];
        for (int i = 0; i < intsId.length; i++) {
            Assert.notNull(intsId[i], MSG_DELETE_RECORD_EMPTY);
            intsTemp[i] = intsId[i];
        }

        Integer intCount = tableUnitDAO.getCountByIdIn(intsTemp);
        Assert.isTrue(intCount == intsId.length, MSG_DELETE_RECORD_BEEN_NULL);

        tableUnitDAO.deleteAllByIdInBatch(Arrays.asList(intsId));
        return intsId;
    }

    // ===================内部=======================

    /**
     * 获取查询范式
     *
     * @return {@link Specification}<{@link TableUnitDO}>
     */
    protected Specification<TableUnitDO> getSpecification(final TableUnitRetrieveDTO modelRetrieve) {
        return (root, query, criteriaBuilder) -> {
            Map<String, String> mapSearch = modelRetrieve.getMapSearch();
            if (MapUtil.isNotEmpty(mapSearch)) {
                List<Predicate> listPredicate = new ArrayList<>();

                String strLike = MapUtil.getStr(mapSearch, TableUnitConstants.UNIT_NAME_ENTITY);
                if (StrUtil.isNotBlank(strLike)) {
                    listPredicate.add(criteriaBuilder.like(root.get(TableUnitDO_.unitName), strLike));
                }

                return criteriaBuilder.and(ArrayUtil.toArray(listPredicate, Predicate.class));
            }
            return null;
        };
    }

    @Override
    @CacheEvict(value = TableUnitConstants.TABLE_ENTITY, allEntries = true)
    public void cacheEvict() {

    }

    // ===================扩展=======================
}